1 module lib.meson; 2 3 import std.file : exists, getcwd, mkdirRecurse; 4 import std.path : buildPath, absolutePath; 5 import std..string : indexOf; 6 import std.regex : ctRegex, matchFirst; 7 import std.stdio : writeln; 8 9 import lib.process : executeAt; 10 import lib.set_compiler; 11 12 /** The options used for CMake */ 13 struct MesonOptions 14 { 15 /** The build config. Defaults to `"release"` */ 16 string buildConfig = "release"; 17 18 /** The backend to use */ 19 string backend = "ninja"; 20 21 /** The compiler to use. If `CC` and `CXX` environment variables are not specified, it defaults to `clang` */ 22 auto compiler = "clang"; 23 } 24 25 /** 26 Configure and build a Meson project at the given paths. 27 28 Params: 29 rootDir = The root path which includes meson.build 30 buildDir = The building directory path 31 options = The options used for Meson 32 33 */ 34 void meson(string rootDir = getcwd(), string buildDir = buildPath(getcwd(), 35 "./build"), MesonOptions options = MesonOptions()) 36 { 37 // compiler 38 const env = set_compiler(options.compiler); 39 40 // build config 41 const buildConfig = convert_build_config(options.buildConfig); 42 43 // sanitizer 44 const sanitizerArgs = convert_sanitizer(options.buildConfig); 45 46 if (!buildDir.exists()) // guess if the folder exists, then it is already configured 47 { 48 configure: // if compile fails, the script will configure and try again 49 // make build dir 50 mkdirRecurse(buildDir); 51 52 // configure 53 executeAt([ 54 "meson", "setup", buildDir, rootDir, "--buildtype", buildConfig, 55 "--backend", options.backend 56 ] ~ sanitizerArgs, rootDir, env); 57 } 58 // build 59 try 60 { 61 executeAt(["meson", "compile", "-C", buildDir], rootDir, env); 62 } 63 catch (Exception ex) 64 { 65 // configure and try again 66 goto configure; 67 } 68 } 69 70 /** Convert D config to Cmake config */ 71 private auto convert_build_config(string buildConfig) 72 { 73 // build config 74 if (buildConfig.indexOf("debug") != -1) 75 { 76 return "debug"; 77 } 78 else if (buildConfig.indexOf("release") != -1) 79 { 80 return "release"; 81 } 82 83 return "debug"; 84 } 85 86 private string[] convert_sanitizer(string buildConfig) 87 { 88 // extract the name of the sanitizer from the build config 89 auto sanitizeMatch = matchFirst(buildConfig, ctRegex!(r"sanitize-(\w*)")); 90 if (!sanitizeMatch.empty() && sanitizeMatch.length == 2) 91 { 92 return ["-Db_sanitize=" ~ sanitizeMatch[1], "-Db_lundef=false"]; 93 } 94 return []; 95 }